using System;
using System.ComponentModel;
using System.Runtime.Serialization;

using SharpGL.Media3D;

namespace SharpGL.SceneGraph.Cameras
{
    /// <summary>
    /// The LookAt camera is a camera that does a 'look at' transformation.
    /// </summary>
    [DataContract()]
    public class LookAtCamera : PerspectiveCamera
    {
        #region Private Fields

        /// <summary>
        /// This is the point in the scene that the camera is pointed at.
        /// </summary>
        [DataMember()]
        private Point3D target = new Point3D(0, 0, 0);

        /// <summary>
        /// This is a point that describes the 'up' direction (normally 0, 0, 1).
        /// Use this to tilt the camera.
        /// </summary>
        [DataMember()]
        private Vector3D upVector = new Vector3D(0, 0, 1);

        #endregion Protected Fields

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="LookAtCamera"/> class.
        /// </summary>
        public LookAtCamera()
        {
            Name = "Camera (Look At)";
        }

        #endregion Constructors

        #region Public Methods

        /// <summary>
        /// This is the class' main function, to override this function and perform a 
        /// perspective transformation.
        /// </summary>
        public override void TransformProjectionMatrix(OpenGL gl)
        {
            if (OpenGL.IsValidContext(gl))
            {
                //  Perform the look at transformation.
                gl.Perspective(FieldOfView, AspectRatio, Near, Far);
                gl.LookAt((double)Position.X, (double)Position.Y, (double)Position.Z,
                    (double)target.X, (double)target.Y, (double)target.Z,
                    (double)upVector.X, (double)upVector.Y, (double)upVector.Z);
            }
        }

        #endregion Public Methods

        #region Public Properties

        /// <summary>
        /// Gets or sets the target.
        /// </summary>
        /// <value>
        /// The target.
        /// </value>
        [Description("The target of the camera (the point it's looking at"), Category("Camera")]
        public Point3D Target
        {
            get { return target; }
            set
            {
                if (target != value)
                {
                    target = value;

                    NotifyPropertyChanged("Target");
                }
            }
        }

        /// <summary>
        /// Gets or sets up point.
        /// </summary>
        /// <value>
        /// Up point.
        /// </value>
        [Description("The up direction, relative to camera. (Controls tilt)."), Category("Camera")]
        public Vector3D UpVector
        {
            get { return upVector; }
            set
            {
                if (upVector != value)
                {
                    upVector = value;

                    NotifyPropertyChanged("UpVector");
                }
            }
        }

        #endregion Public Properties
    }
}
